interface ViewportOffsetResult {
  /**
   * 元素相对于视口左侧的距离
   */
  left: number
  /**
   * 元素相对于视口顶部的距离
   */
  top: number
  /**
   * 元素相对于视口右侧的距离
   */
  right: number
  /**
   * 元素相对于视口底部的距离
   */
  bottom: number
  /**
   * 元素相对于视口左侧的距离，包括body的滚动距离
   */
  rightIncludeBody: number
  /**
   * 元素相对于视口顶部的距离，包括body的滚动距离
   */
  bottomIncludeBody: number
}

export function getBoundingClientRect(element: Element) {
  if (!element || !element.getBoundingClientRect) {
    throw new Error('Cannot get bounding client rect of undefined')
  }
  return element.getBoundingClientRect()
}

function trim(string: string) {
  return (string || '').replace(/^[\s\uFEFF]+|[\s\uFEFF]+$/g, '')
}

/**
 * 元素是否包含某个class
 * @param el 元素
 * @param cls 类名
 * @returns
 */
export function hasClass(el: Element, cls: string) {
  // 判断el和cls是否存在，如果不存在则返回false
  if (!el || !cls) return false
  // 判断cls是否包含空格，如果包含则抛出错误
  if (cls.indexOf(' ') !== -1) throw new Error('className should not contain space.')
  // 判断el是否包含classList属性，如果包含则使用classList.contains方法判断是否存在cls
  if (el.classList) {
    return el.classList.contains(cls)
    // 否则使用indexOf方法判断el.className中是否包含cls
  } else {
    return (' ' + el.className + ' ').indexOf(' ' + cls + ' ') > -1
  }
}

/**
 * 元素增加类名
 * @param el 元素
 * @param cls 类名
 * @returns
 */
export function addClass(el: Element, cls: string) {
  // 如果el不存在，则返回
  if (!el) return
  // 获取el的className
  let curClass = el.className
  // 将cls字符串按空格分割成数组
  const classes = (cls || '').split(' ')

  // 遍历数组
  for (let i = 0, j = classes.length; i < j; i++) {
    // 获取数组中的每一个元素
    const clsName = classes[i]
    // 如果元素不存在，则跳过
    if (!clsName) continue

    // 如果el存在classList属性，则添加clsName
    if (el.classList) {
      el.classList.add(clsName)
      // 如果el不存在classList属性，且el没有clsName这个class，则添加clsName
    } else if (!hasClass(el, clsName)) {
      curClass += ' ' + clsName
    }
  }
  // 如果el不存在classList属性，则将curClass赋值给el的className
  if (!el.classList) {
    el.className = curClass
  }
}

/**
 * 移除元素的类名
 * @param el 元素
 * @param cls
 * @returns
 */
export function removeClass(el: Element, cls: string) {
  // 如果el或cls不存在，则返回
  if (!el || !cls) return
  // 将cls字符串按空格分割成数组
  const classes = cls.split(' ')
  // 将el的className属性值添加一个空格，方便后续操作
  let curClass = ' ' + el.className + ' '

  // 遍历classes数组
  for (let i = 0, j = classes.length; i < j; i++) {
    // 获取当前class名
    const clsName = classes[i]
    // 如果当前class名为空，则跳过
    if (!clsName) continue

    // 如果el的classList属性存在，则调用classList.remove方法移除当前class名
    if (el.classList) {
      el.classList.remove(clsName)
      // 否则，调用hasClass方法判断el是否包含当前class名，如果包含，则将当前class名从curClass中移除
    } else if (hasClass(el, clsName)) {
      curClass = curClass.replace(' ' + clsName + ' ', ' ')
    }
  }
  // 如果el的classList属性不存在，则将curClass中的空格去掉，并赋值给el的className属性
  if (!el.classList) {
    el.className = trim(curClass)
  }
}

/**
 * 用于获取元素在视口中的偏移量
 * @param element 元素
 * @returns
 */
export function getViewportOffset(element: Element): ViewportOffsetResult {
  // 获取文档的根元素
  const doc = document.documentElement

  // 获取文档的滚动距离和边框宽度
  const docScrollLeft = doc.scrollLeft
  const docScrollTop = doc.scrollTop
  const docClientLeft = doc.clientLeft
  const docClientTop = doc.clientTop

  // 获取页面的滚动距离
  const pageXOffset = window.pageXOffset
  const pageYOffset = window.pageYOffset

  // 获取元素的边界矩形
  const box = getBoundingClientRect(element)

  // 解构边界矩形，获取元素的左、上、宽、高
  const { left: retLeft, top: rectTop, width: rectWidth, height: rectHeight } = box as DOMRect

  // 计算元素的滚动距离和偏移量
  const scrollLeft = (pageXOffset || docScrollLeft) - (docClientLeft || 0)
  const scrollTop = (pageYOffset || docScrollTop) - (docClientTop || 0)
  const offsetLeft = retLeft + pageXOffset
  const offsetTop = rectTop + pageYOffset

  // 计算元素的左、上偏移量
  const left = offsetLeft - scrollLeft
  const top = offsetTop - scrollTop

  // 获取视口的宽度和高度
  const clientWidth = window.document.documentElement.clientWidth
  const clientHeight = window.document.documentElement.clientHeight
  // 返回元素的偏移量结果
  return {
    left: left, // 左边距
    top: top, // 上边距
    right: clientWidth - rectWidth - left, // 右边距
    bottom: clientHeight - rectHeight - top, // 下边距
    rightIncludeBody: clientWidth - left, // 包含body的右边距
    bottomIncludeBody: clientHeight - top // 包含body的下边距
  }
}

// export function useRafThrottle<T extends FunctionArgs>(fn: T): T {
//   let locked = false
//   // @ts-ignore
//   return function (...args: any[]) {
//     if (locked) return
//     locked = true
//     window.requestAnimationFrame(() => {
//       // @ts-ignore
//       fn.apply(this, args)
//       locked = false
//     })
//   }
// }
